/*********************************************************************************
  *Copyright (c)    2021   xldeng
  *FileName:        configTest.cc.c
  *Author:          xldeng
  *Version:         1.0
  *Date:            2021/2/26 21:14
  *Description:     
  *Others:          
  *Function List:   
     1.…………
  *History:  
     1.Date:
       Author:
       Modification:
**********************************************************************************/
#include "config.h"
#include "log.h"
#include <yaml-cpp/yaml.h>

sylar::ConfigVar<int>::ptr g_int_value_config =
        sylar::Config::Lookup("system.port", (int) 8080, "system port");
sylar::ConfigVar<float>::ptr g_int_valuex_config =
        sylar::Config::Lookup("system.port", (float) 8080, "system port");
sylar::ConfigVar<float>::ptr g_float_value_config =
        sylar::Config::Lookup("system.value", (float) 15.0f, "system port");
sylar::ConfigVar<std::vector<int>>::ptr g_int_vector_value_config =
        sylar::Config::Lookup("system.int_vector", std::vector<int>{1, 2}, "system int vector");
sylar::ConfigVar<std::list<int>>::ptr g_int_list_value_config =
        sylar::Config::Lookup("system.int_list", std::list<int>{3, 4}, "system int list");
sylar::ConfigVar<std::set<int>>::ptr g_int_set_value_config =
        sylar::Config::Lookup("system.int_set", std::set<int>{3, 4}, "system int set");
sylar::ConfigVar<std::unordered_set<int>>::ptr g_int_unordered_set_value_config =
        sylar::Config::Lookup("system.int_unordered_set", std::unordered_set<int>{3, 4}, "system int unordered_set");
sylar::ConfigVar<std::map<std::string, int>>::ptr g_str_int_map_value_config =
        sylar::Config::Lookup("system.str_int_map", std::map<std::string, int>{{"k1", 5}}, "system str-int map");
sylar::ConfigVar<std::unordered_map<std::string, int>>::ptr g_str_int_umap_value_config =
        sylar::Config::Lookup("system.str_int_umap", std::unordered_map<std::string, int>{{"k1", 5}},
                              "system str-int umap");

void print_yaml(const YAML::Node &node, int level) {
    if (node.IsScalar()) {
        SYLAR_LOG_INFO(SYLAR_LOG_ROOT()) << std::string(level * 4, ' ')
                                         << node.Scalar() << "-" << node.Type() << "-" << level;
    } else if (node.IsNull()) {
        SYLAR_LOG_INFO(SYLAR_LOG_ROOT()) << std::string(level * 4, ' ')
                                         << "NULL" << "-" << node.Type() << "-" << level;
    } else if (node.IsMap()) {
        for (auto it = node.begin(); it != node.end(); it++) {
            SYLAR_LOG_INFO(SYLAR_LOG_ROOT()) << std::string(level * 4, ' ')
                                             << it->first << "-" << it->second.Type() << "-" << level;
            print_yaml(it->second, level + 1);
        }
    } else if (node.IsSequence()) {
        for (size_t i = 0; i < node.size(); ++i) {
            SYLAR_LOG_INFO(SYLAR_LOG_ROOT()) << std::string(level * 4, ' ')
                                             << i << "-" << node[i].Type() << "-" << level;
            print_yaml(node[i], level + 1);
        }
    }

}

void test_yaml() {
    YAML::Node root = YAML::LoadFile("./config/test.yml");
    print_yaml(root, 0);
}

void test_config() {
    SYLAR_LOG_INFO(SYLAR_LOG_ROOT()) << "before: " << g_int_value_config->getVal();
    SYLAR_LOG_INFO(SYLAR_LOG_ROOT()) << "before: " << g_float_value_config->toString();

#define XX(g_var, name, prefix)\
    {\
        auto v = g_var->getVal();\
        for (auto &i : v) {\
            SYLAR_LOG_INFO(SYLAR_LOG_ROOT()) << #prefix " :" #name  << i;\
        }\
        SYLAR_LOG_INFO(SYLAR_LOG_ROOT()) << #prefix " :" #name  " yaml: "<< g_var->toString();\
    }

#define XX_M(g_var, name, prefix)\
    {\
        auto v = g_var->getVal();\
        for (auto &i : v) {\
            SYLAR_LOG_INFO(SYLAR_LOG_ROOT()) << #prefix " :" #name  "{"<< i.first <<" , " << i.second <<"}";\
        }\
        SYLAR_LOG_INFO(SYLAR_LOG_ROOT()) << #prefix " :" #name  " yaml: "<< g_var->toString();\
    }

    XX(g_int_vector_value_config, int_vector, before);
    XX(g_int_list_value_config, int_list, before);
    XX(g_int_set_value_config, int_set, before);
    XX(g_int_unordered_set_value_config, int_unordered_set, before);
    XX_M(g_str_int_map_value_config, str_int_map, before);
    XX_M(g_str_int_umap_value_config, str_int_umap, before);

    YAML::Node root = YAML::LoadFile("./config/test.yml");
    sylar::Config::LoadFromYaml(root);

    SYLAR_LOG_INFO(SYLAR_LOG_ROOT())

        << "after: " << g_int_value_config->

                getVal();
    SYLAR_LOG_INFO(SYLAR_LOG_ROOT())

        << "after: " << g_float_value_config->

                toString();

    XX(g_int_vector_value_config, int_vector, after);
    XX(g_int_list_value_config, int_list, after);
    XX(g_int_set_value_config, int_set, after);
    XX(g_int_unordered_set_value_config, int_unordered_set, after);
    XX_M(g_str_int_map_value_config, str_int_map, after);
    XX_M(g_str_int_umap_value_config, str_int_umap, after);
}

class Person {
public:
    Person() {}

    Person(std::string name, int age, bool sex = 0) : m_name(name), m_age(age), m_sex(sex) {}

    bool operator==(const Person &lhs) const{
        return m_name == lhs.m_name && m_age == lhs.m_age && m_sex == lhs.m_sex;
    }

    std::string toString() const {
        std::stringstream ss;
        ss << "[Person name=" << m_name
           << "age=" << m_age
           << "sex=" << m_sex
           << "]";
        return ss.str();
    }

    std::string getName() const { return m_name; }

    int getAge() const { return m_age; }

    bool getSex() const { return m_sex; }

private:
    std::string m_name;
    int m_age = 0;
    bool m_sex = 0;
};

namespace sylar {
    template<>
    class LexicalCast<std::string, Person> {
    public:
        Person operator()(const std::string &v) {
            YAML::Node node = YAML::Load(v);
            return Person(node["name"].as<std::string>(), node["age"].as<int>(), node["sex"].as<bool>());
        }
    };

    template<>
    class LexicalCast<Person, std::string> {
    public:
        std::string operator()(const Person &v) {
            YAML::Node node;
            std::stringstream ss;
            node["name"] = v.getName();
            node["age"] = v.getAge();
            node["sex"] = v.getSex();
            ss << node;
            return ss.str();
        }
    };
}
sylar::ConfigVar<Person>::ptr g_person =
        sylar::Config::Lookup("class.person", Person(), "class person");

void test_class() {
    g_person->addListener([](const Person& old_value,const Person& new_value){
        SYLAR_LOG_INFO(SYLAR_LOG_ROOT()) << "old_value="<< old_value.toString() << " __ " << "new_value="<<new_value.toString();
    });
    SYLAR_LOG_INFO(SYLAR_LOG_ROOT()) << g_person->getVal().toString() << " - " << g_person->toString();

    YAML::Node root = YAML::LoadFile("./config/test.yml");
    sylar::Config::LoadFromYaml(root);
    SYLAR_LOG_INFO(SYLAR_LOG_ROOT()) << g_person->getVal().toString() << " - " << g_person->toString();
}

int main() {
//    SYLAR_LOG_INFO(SYLAR_LOG_ROOT()) << g_int_value_config->getVal();
//    SYLAR_LOG_INFO(SYLAR_LOG_ROOT()) << g_int_value_config->toString();
//    sylar::ConfigVar<int>::ptr int_value_config =
//            sylar::Config::Lookup("system.port", (int) 8080, "system port");
//    SYLAR_LOG_INFO(SYLAR_LOG_ROOT()) << int_value_config->getVal();
//    SYLAR_LOG_INFO(SYLAR_LOG_ROOT()) << int_value_config->toString();
//    test_yaml();
//    test_config();
    test_class();
    return 0;
}
